package simulation;

import factory.Factory;
import gameobject.Sprite;

import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

/**
 * Game handles updating and painting
 * of the sprites that are currently
 * on the screen. Works together with
 * Observer to control when sprites
 * react to events.
 *
 */
/**
 * @author Volodymyr, Rex
 *
 */
public class Game {
    private int myGenerationDelayTime;
    private Factory myFactory;
    private Observer myObserver;
    private List<Sprite> mySprites;
    private Canvas myCanvas;

    /**
     * Constructor for a Game.
     * @param canvas on which the game will be displayed
     */
    public Game (Canvas canvas) {
        myCanvas = canvas;
        mySprites = new ArrayList<Sprite>();
        myObserver = new Observer(this);
        myFactory =
                instantiateFactory(getResource("FactoryClass"),
                                   getResource("InitialObjects"),
                                   getResource("FactoryDelayTime"));
    }

    private Factory instantiateFactory(String factoryClass,
            String objectsToGenerate, String delay) {
        myGenerationDelayTime = Integer.parseInt(delay);
        try {
            Class<?> factoryClassObject = Class.forName(factoryClass);
            return (Factory) factoryClassObject.getConstructor(
                    String.class, int.class, Game.class).newInstance(
                            objectsToGenerate, myGenerationDelayTime, this);
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Updates the movement of sprites currently
     * in play.
     */
    public void update() {
        myObserver.update();
        synchronized (mySprites) {
            for (Sprite s : mySprites) {
                s.update();
            }
        }
    }

    /**
     * Paints the sprites in play.
     * @param g used to paint
     */
    public void paint (Graphics g) {
        synchronized (mySprites) {
            for (Sprite s : mySprites) {
                s.paint(g);
            }
        }
    }

    /**
     * Sets the time delay.
     * @param time of the delay
     */
    public void setGenerationDelayTime(int time) {
        myGenerationDelayTime = time;
    }

    /**
     * @return the list of sprites
     * currently in play
     */
    public List<Sprite> getSpriteList () {
        return mySprites;
    }

    /**
     * @return the dimensions of the canvas
     */
    public Dimension getCanvasDimension() {
        return myCanvas.getSize();
    }

    /**
     * Called by Observer when the game over
     * conditions are met.
     */
    public void gameOver() {
        for (Sprite s: mySprites) {
            s.die();
        }
        mySprites.clear();
        myFactory.stop();
        myCanvas.gameOver();
    }

    /**
     * Adds a sprite to the game.
     * @param s the sprite to be added
     */
    public void addSprite(Sprite s) {
        synchronized (mySprites) {
            mySprites.add(s);
        }
    }

    /**
     * @return the observer that the game
     * is using
     */
    public Observer getObserver () {
        return myObserver;
    }

    /**
     * @param res the name of the resource
     * @return the resource package to use
     */
    public String getResource (String res) {
        return myCanvas.getResource(res);
    }
}
